import tkinter as tk
from tkinter import colorchooser, messagebox
import os
from models import LabelItem, LineItem
from config import APP_TITLE, DEFAULT_TEXT, MIN_SCALE, MAX_SCALE, ZOOM_FACTOR


class EventHandlers:
    """事件处理相关功能"""
    
    def __init__(self, app):
        self.app = app

    def bind_events(self):
        """绑定所有事件"""
        self.app.canvas.bind("<Button-1>", self.on_canvas_click)
        self.app.canvas.bind("<B1-Motion>", self.on_canvas_drag)
        self.app.canvas.bind("<ButtonRelease-1>", self.on_canvas_release)
        self.app.canvas.bind("<Button-2>", self.on_middle_click)  # 中键按下
        self.app.canvas.bind("<B2-Motion>", self.on_middle_drag)  # 中键拖动
        self.app.canvas.bind("<ButtonRelease-2>", self.on_middle_release)  # 中键释放
        self.app.canvas.bind("<Motion>", self.on_mouse_move)
        self.app.canvas.bind("<MouseWheel>", self.on_mouse_wheel)
        self.app.canvas.bind("<Button-4>", lambda e: self.zoom(ZOOM_FACTOR))
        self.app.canvas.bind("<Button-5>", lambda e: self.zoom(1/ZOOM_FACTOR))
        self.app.root.bind("<Escape>", self.clear_selection)

    def on_canvas_click(self, event):
        """画布点击事件"""
        # 优先检查是否点击了控制点
        if self.app.selected_line:
            point_collision = self._check_point_collision(event)
            if point_collision:
                self.app.dragging_point = point_collision
                return
        
        # 检查是否点击了选中遮罩的调整手柄
        if self.app.selected_mask:
            handle = self.app._check_mask_handle_collision(event.x, event.y, self.app.selected_mask)
            if handle:
                self.app.resizing_mask = self.app.selected_mask
                self.app.resize_handle = handle
                self.app.resize_start_pos = (event.x, event.y)
                return
        
        # 检查是否点击了文字标注（最高优先级）
        click_x = event.x / self.app.scale
        click_y = event.y / self.app.scale
        
        clicked_label = None
        # 从后往前检查（后添加的在上层）
        for lbl in reversed(self.app.labels):
            if self._is_point_in_label(click_x, click_y, lbl):
                clicked_label = lbl
                break
        
        if clicked_label:
            self.app.selected_label = clicked_label
            self.app.selected_mask = None  # 清除遮罩选择
            self.app.selected_line = None  # 清除线条选择
            # 记录点击位置与标注位置的偏移
            self.app.label_drag_offset = (click_x - clicked_label.x, click_y - clicked_label.y)
            # 同步更新UI控件
            self._sync_ui_with_selected_label()
            self.app.update_preview()
            return
        
        # 检查是否点击了遮罩（用于选择和拖动）
        clicked_mask = self.app._check_mask_collision(event.x, event.y)
        if clicked_mask:
            # 选中遮罩
            self.app.selected_mask = clicked_mask
            self.app.clear_selection()  # 清除其他选择
            self.app.refresh_mask_list()
            self._sync_ui_with_selected_mask()
            
            # 开始拖动
            self.app.dragging_mask = clicked_mask
            mask_x = int(clicked_mask.x * self.app.scale)
            mask_y = int(clicked_mask.y * self.app.scale)
            self.app.mask_drag_offset = (event.x - mask_x, event.y - mask_y)
            self.app.update_preview()
            return
        
        # 遮罩模式处理（创建新遮罩）
        if self.app.mask_mode:
            self._handle_mask_click(event)
            return
            
        if self.app.line_mode:
            click_point = (event.x/self.app.scale, event.y/self.app.scale)
            line_type = getattr(self.app, 'line_type_var', None)
            current_line_type = line_type.get() if line_type else "straight"
            
            # 获取线条设置
            line_width = getattr(self.app, 'line_width_var', None)
            width = line_width.get() if line_width else 2
            color = getattr(self.app, 'line_color', "#000000")
            
            if current_line_type == "straight":
                # 直线模式：需要2个点
                if len(self.app.temp_line_points) == 0:
                    # 第一个点
                    self.app.temp_line_points.append(click_point)
                elif len(self.app.temp_line_points) == 1:
                    # 第二个点，完成直线
                    self.app.temp_line_points.append(click_point)
                    ln = LineItem(self.app.temp_line_points.copy(), color, width, "straight")
                    self.app.lines.append(ln)
                    self._finish_line_drawing()
                    
            elif current_line_type == "polyline":
                # 折线模式：需要3个点
                if len(self.app.temp_line_points) < 2:
                    # 前两个点
                    self.app.temp_line_points.append(click_point)
                elif len(self.app.temp_line_points) == 2:
                    # 第三个点，完成折线
                    self.app.temp_line_points.append(click_point)
                    ln = LineItem(self.app.temp_line_points.copy(), color, width, "polyline")
                    self.app.lines.append(ln)
                    self._finish_line_drawing()
            
            # 更新临时预览
            self._update_temp_line_preview()
            return
        
        # 如果没有点击到任何元素，清除选择
        if not self.app.line_mode:
            self.app.selected_label = None
            self.app.selected_mask = None
            self.app.selected_line = None
            self.app.update_preview()

    def on_canvas_drag(self, event):
        """画布拖拽事件 - 优化性能"""
        # 优先处理控制点拖拽
        if hasattr(self.app, 'dragging_point') and self.app.dragging_point:
            self._handle_point_drag(event)
            return
        
        # 处理遮罩调整大小
        if self.app.resizing_mask and self.app.resize_handle:
            self._handle_mask_resize(event)
            return
        
        # 处理遮罩拖动
        if self.app.dragging_mask:
            self._handle_mask_move(event)
            return
        
        # 处理遮罩绘制
        if self.app.mask_drawing:
            self._handle_mask_drag(event)
            return
            
        if not self.app.selected_label:
            return
            
        # 使用偏移量计算新位置
        new_x = event.x / self.app.scale - self.app.label_drag_offset[0]
        new_y = event.y / self.app.scale - self.app.label_drag_offset[1]
        
        # 限制拖动范围，防止拖出图像边界
        if self.app.image:
            iw, ih = self.app.image.size
            new_x = max(0, min(new_x, iw - 10))
            new_y = max(0, min(new_y, ih - 10))
        
        self.app.selected_label.x = int(new_x)
        self.app.selected_label.y = int(new_y)
        
        # 优化：拖动时只更新画布，不刷新整个界面
        self._quick_update_canvas()

    def on_canvas_release(self, event):
        """左键释放事件"""
        # 结束控制点拖拽
        if hasattr(self.app, 'dragging_point') and self.app.dragging_point:
            self.app.dragging_point = None
            # 如果刚刚在拖拽控制点，更新线条列表
            if self.app.selected_line:
                self.app.refresh_line_list()
        
        # 结束遮罩调整大小
        if self.app.resizing_mask:
            self.app.resizing_mask = None
            self.app.resize_handle = None
            self.app.resize_start_pos = None
            # 更新遮罩列表
            self.app.refresh_mask_list()
            self.app.update_preview()  # 完整更新
        
        # 结束遮罩拖动
        if self.app.dragging_mask:
            self.app.dragging_mask = None
            self.app.mask_drag_offset = None
            # 更新遮罩列表
            self.app.refresh_mask_list()
            self.app.update_preview()  # 完整更新
        
        # 结束遮罩绘制
        if self.app.mask_drawing:
            self._finish_mask_drawing(event)
            return
            
        # 拖动结束后完整更新界面
        if self.app.selected_label:
            self.app.refresh_label_list()  # 更新标注列表显示
        self.app.update_preview()  # 完整更新画布

    def on_middle_click(self, event):
        """中键按下事件"""
        self.app.canvas_drag_start = (event.x, event.y)
        self.app.canvas_drag_mode = True
        self.app.canvas.configure(cursor="fleur")  # 改变光标为移动样式

    def on_middle_drag(self, event):
        """中键拖动事件 - 移动画布视图"""
        if not self.app.canvas_drag_mode or not self.app.canvas_drag_start:
            return
            
        # 计算拖动距离
        dx = event.x - self.app.canvas_drag_start[0]
        dy = event.y - self.app.canvas_drag_start[1]
        
        # 获取当前滚动位置
        x_view = self.app.canvas.canvasx(0)
        y_view = self.app.canvas.canvasy(0)
        
        # 计算新的滚动位置
        new_x = x_view - dx
        new_y = y_view - dy
        
        # 获取滚动区域
        scroll_region = self.app.canvas.cget("scrollregion").split()
        if len(scroll_region) == 4:
            min_x, min_y, max_x, max_y = map(float, scroll_region)
            canvas_width = self.app.canvas.winfo_width()
            canvas_height = self.app.canvas.winfo_height()
            
            # 限制滚动范围
            if max_x > canvas_width:
                new_x = max(min_x, min(new_x, max_x - canvas_width))
            else:
                new_x = min_x
                
            if max_y > canvas_height:
                new_y = max(min_y, min(new_y, max_y - canvas_height))
            else:
                new_y = min_y
            
            # 应用滚动
            self.app.canvas.xview_moveto(new_x / max_x if max_x > 0 else 0)
            self.app.canvas.yview_moveto(new_y / max_y if max_y > 0 else 0)
        
        # 更新拖动起始点
        self.app.canvas_drag_start = (event.x, event.y)

    def on_middle_release(self, event):
        """中键释放事件"""
        self.app.canvas_drag_mode = False
        self.app.canvas_drag_start = None
        self.app.canvas.configure(cursor="")  # 恢复默认光标

    def on_mouse_move(self, event):
        """鼠标移动事件"""
        # 处理控制点拖拽
        if hasattr(self.app, 'dragging_point') and self.app.dragging_point:
            self._handle_point_drag(event)
            return
            
        if self.app.line_mode and self.app.temp_line_points:
            # 清除之前的预览线 - 包括辅助线
            if hasattr(self.app, 'temp_preview_line_id') and self.app.temp_preview_line_id:
                self.app.canvas.delete(self.app.temp_preview_line_id)
                self.app.temp_preview_line_id = None
            if hasattr(self.app, 'temp_preview_helper_id') and self.app.temp_preview_helper_id:
                self.app.canvas.delete(self.app.temp_preview_helper_id)
                self.app.temp_preview_helper_id = None
            
            # 绘制从最后一个点到鼠标位置的预览线
            last_point = self.app.temp_line_points[-1]
            x1 = last_point[0] * self.app.scale
            y1 = last_point[1] * self.app.scale
            x2 = event.x
            y2 = event.y
            
            # 使用更平滑的预览线绘制
            self._draw_smooth_preview_line(x1, y1, x2, y2)

    def on_mouse_wheel(self, event):
        """鼠标滚轮事件"""
        self.zoom(ZOOM_FACTOR if event.delta > 0 else 1/ZOOM_FACTOR)

    def zoom(self, factor):
        """缩放操作"""
        if not self.app.image:
            return
        self.app.scale = max(MIN_SCALE, min(MAX_SCALE, self.app.scale * factor))
        self.app.update_preview()
        self.app.update_zoom_label()

    def on_label_list_select(self, event):
        """标注列表选择事件"""
        sel = self.app.label_list.curselection()
        if not sel:
            return
        idx = sel[0]
        self.app.selected_label = self.app.labels[idx]
        self.app.text_var.set(self.app.selected_label.text)
        self.app.size_var.set(self.app.selected_label.font_size)
        self.app.bold_var.set(self.app.selected_label.bold)
        self.app.color_preview.configure(bg=self.app.selected_label.color)
        
        # 更新字体选择
        if hasattr(self.app, 'font_var') and self.app.selected_label.font_path:
            font_name = os.path.basename(self.app.selected_label.font_path)
            self.app.font_var.set(font_name)
        
        self.app.selected_line = None
        self.app.update_preview()

    def on_line_list_select(self, event):
        """标线列表选择事件"""
        sel = self.app.line_list.curselection()
        if not sel:
            return
        idx = sel[0]
        self.app.selected_line = self.app.lines[idx]
        self.app.selected_label = None
        
        # 同步线条设置到UI控件
        self._sync_ui_with_selected_line()
        self.app.update_preview()

    def _sync_ui_with_selected_line(self):
        """同步UI控件与选中的线条"""
        if not self.app.selected_line:
            return
        
        # 临时标记，避免触发回调
        self.app._syncing_line_ui = True
        
        try:
            # 更新线条类型
            if hasattr(self.app, 'line_type_var'):
                self.app.line_type_var.set(self.app.selected_line.line_type)
            
            # 更新线条粗细
            if hasattr(self.app, 'line_width_var'):
                self.app.line_width_var.set(self.app.selected_line.width)
            
            # 更新线条颜色
            if hasattr(self.app, 'line_color_preview'):
                self.app.line_color_preview.configure(bg=self.app.selected_line.color)
                self.app.line_color = self.app.selected_line.color
        finally:
            # 清除临时标记
            self.app._syncing_line_ui = False

    def clear_selection(self, event=None):
        """清除选择"""
        self.app.selected_label = None
        self.app.selected_line = None
        self.app.selected_mask = None
        
        # 清除遮罩拖动状态
        self.app.dragging_mask = None
        self.app.mask_drag_offset = None
        self.app.resizing_mask = None
        self.app.resize_handle = None
        self.app.resize_start_pos = None
        if hasattr(self.app, 'label_list'):
            self.app.label_list.selection_clear(0, tk.END)
        if hasattr(self.app, 'line_list'):
            self.app.line_list.selection_clear(0, tk.END)
        if hasattr(self.app, 'mask_list'):
            self.app.mask_list.selection_clear(0, tk.END)
        
        # 如果在标线模式中，清除临时绘制状态
        if self.app.line_mode:
            self.app.temp_line_points.clear()
            self._clear_temp_line_preview()
            if hasattr(self.app, 'temp_preview_line_id') and self.app.temp_preview_line_id:
                self.app.canvas.delete(self.app.temp_preview_line_id)
                self.app.temp_preview_line_id = None
        
        self.app.update_preview()

    def choose_color(self):
        """选择颜色"""
        color = colorchooser.askcolor(color=self.app.color_preview["bg"])[1]
        if not color:
            return
        self.app.color_preview.configure(bg=color)
        if self.app.selected_label:
            self.app.selected_label.color = color
            self.app.update_selected_label()

    def add_label(self):
        """添加标注"""
        if not self.app.image:
            return
        iw, ih = self.app.image.size
        initial_text = self.app.text_var.get().strip() or DEFAULT_TEXT
        
        # 获取当前选择的字体路径
        font_path = self.app.current_font_path
        if hasattr(self.app, 'font_var') and self.app.font_var.get():
            selected_font_name = self.app.font_var.get()
            for fp in self.app.available_fonts:
                if os.path.basename(fp) == selected_font_name:
                    font_path = fp
                    break
        
        lbl = LabelItem(
            initial_text, iw//2, ih//2, font_path, 
            int(self.app.size_var.get()), 
            self.app.color_preview["bg"], 
            self.app.bold_var.get()
        )
        self.app.labels.append(lbl)
        self.app.refresh_label_list(select_last=True)
        self.app.selected_label = lbl
        self.app.update_preview()

    def delete_selected(self):
        """删除选中项"""
        if self.app.selected_label:
            try:
                idx = self.app.labels.index(self.app.selected_label)
                self.app.labels.pop(idx)
            except ValueError:
                pass
            self.app.selected_label = None
            self.app.refresh_label_list()
            self.app.update_preview()
            return
            
        if self.app.selected_line:
            try:
                idx = self.app.lines.index(self.app.selected_line)
                self.app.lines.pop(idx)
            except ValueError:
                pass
            self.app.selected_line = None
            self.app.refresh_line_list()
            self.app.update_preview()
            return
            
        if self.app.selected_mask:
            try:
                idx = self.app.masks.index(self.app.selected_mask)
                self.app.masks.pop(idx)
            except ValueError:
                pass
            self.app.selected_mask = None
            self.app.refresh_mask_list()
            self.app.update_preview()

    def clear_all_annotations(self):
        """一键清空所有标注"""
        from tkinter import messagebox
        
        # 统计要删除的项目数量
        total_count = len(self.app.labels) + len(self.app.lines) + len(self.app.masks)
        
        if total_count == 0:
            messagebox.showinfo("提示", "当前没有任何标注需要清除。")
            return
        
        # 确认对话框
        result = messagebox.askyesno(
            "确认清空", 
            f"即将清除所有标注内容：\n"
            f"• 文字标注：{len(self.app.labels)}个\n"
            f"• 线条标注：{len(self.app.lines)}个\n"
            f"• 遮罩：{len(self.app.masks)}个\n\n"
            f"此操作不可撤销，确定要继续吗？",
            icon="warning"
        )
        
        if result:
            # 清空所有列表
            self.app.labels.clear()
            self.app.lines.clear()
            self.app.masks.clear()
            
            # 清除选择状态
            self.app.selected_label = None
            self.app.selected_line = None
            self.app.selected_mask = None
            
            # 清除拖动状态
            self.clear_selection()
            
            # 刷新所有列表和显示
            self.app.refresh_label_list()
            self.app.refresh_line_list()
            self.app.refresh_mask_list()
            self.app.update_preview()
            
            messagebox.showinfo("完成", f"已成功清除{total_count}个标注项目。")

    def update_selected_label(self):
        """更新选中的标注"""
        if not self.app.selected_label:
            # 即使没有选中标注，也要更新当前字体路径
            self._update_current_font_path()
            return
        
        # 如果正在同步UI，跳过更新以避免循环
        if getattr(self.app, '_syncing_label_ui', False):
            return
            
        self.app.selected_label.text = self.app.text_var.get()
        try:
            self.app.selected_label.font_size = int(self.app.size_var.get())
        except ValueError:
            pass
        self.app.selected_label.bold = self.app.bold_var.get()
        self.app.selected_label.color = self.app.color_preview["bg"]
        
        # 更新字体路径
        if hasattr(self.app, 'font_var') and self.app.font_var.get():
            selected_font_name = self.app.font_var.get()
            for font_path in self.app.available_fonts:
                if os.path.basename(font_path) == selected_font_name:
                    self.app.selected_label.font_path = font_path
                    self.app.current_font_path = font_path  # 同步更新当前字体路径
                    break
        
        self.app.refresh_label_list()
        self.app.update_preview()

    def update_selected_line(self):
        """更新选中的线条属性"""
        if not self.app.selected_line:
            return
        
        # 如果正在同步UI，跳过更新以避免循环
        if getattr(self.app, '_syncing_line_ui', False):
            return
            
        # 更新线条类型
        if hasattr(self.app, 'line_type_var'):
            self.app.selected_line.line_type = self.app.line_type_var.get()
        
        # 更新线条粗细
        if hasattr(self.app, 'line_width_var'):
            try:
                self.app.selected_line.width = int(self.app.line_width_var.get())
            except ValueError:
                pass
        
        # 更新线条颜色
        if hasattr(self.app, 'line_color'):
            self.app.selected_line.color = self.app.line_color
        
        self.app.refresh_line_list()
        self.app.update_preview()

    def clear_temp_line_state(self):
        """清除临时线条状态"""
        self.app.temp_line_points.clear()
        self._clear_temp_line_preview()
        if hasattr(self.app, 'temp_preview_line_id') and self.app.temp_preview_line_id:
            self.app.canvas.delete(self.app.temp_preview_line_id)
            self.app.temp_preview_line_id = None
        if hasattr(self.app, 'temp_preview_helper_id') and self.app.temp_preview_helper_id:
            self.app.canvas.delete(self.app.temp_preview_helper_id)
            self.app.temp_preview_helper_id = None

    def _draw_smooth_preview_line(self, x1, y1, x2, y2):
        """绘制平滑的预览线"""
        # 主预览线 - 更粗更明显
        self.app.temp_preview_line_id = self.app.canvas.create_line(
            x1, y1, x2, y2, fill="#4da6ff", dash=(4, 2), width=2,
            smooth=True, capstyle=tk.ROUND, splinesteps=24
        )
        # 抗锯齿辅助线
        self.app.temp_preview_helper_id = self.app.canvas.create_line(
            x1+0.5, y1+0.5, x2+0.5, y2+0.5, fill="#b3d9ff", dash=(4, 2), width=1,
            smooth=True, capstyle=tk.ROUND, splinesteps=24
        )

    def _handle_point_drag(self, event):
        """处理控制点拖拽"""
        if not self.app.selected_line or not self.app.dragging_point:
            return
            
        point_index, _ = self.app.dragging_point
        # 更新点的位置
        new_x = event.x / self.app.scale
        new_y = event.y / self.app.scale
        
        # 限制拖动范围
        if self.app.image:
            iw, ih = self.app.image.size
            new_x = max(0, min(new_x, iw))
            new_y = max(0, min(new_y, ih))
            
        self.app.selected_line.points[point_index] = (new_x, new_y)
        
        # 只更新画布，不刷新列表（性能优化）
        self._quick_update_canvas()

    def _check_point_collision(self, event):
        """检查鼠标是否点击了控制点"""
        if not self.app.selected_line:
            return None
            
        click_x = event.x
        click_y = event.y
        
        for i, point in enumerate(self.app.selected_line.points):
            point_x = int(point[0] * self.app.scale)
            point_y = int(point[1] * self.app.scale)
            
            # 扩大检测范围，使其更容易点击
            distance = abs(click_x - point_x) + abs(click_y - point_y)  # 曼哈顿距离
            if distance <= 10:  # 增大检测范围
                print(f"点击了控制点 {i}: ({point_x}, {point_y}), 点击位置: ({click_x}, {click_y})")
                return (i, point)
        return None

    # 遮罩相关方法
    def _handle_mask_click(self, event):
        """处理遮罩模式点击"""
        # 开始绘制新遮罩
        self.app.mask_drawing = True
        self.app.mask_start_pos = (event.x / self.app.scale, event.y / self.app.scale)
        
        # 清除之前的选择
        self.app.selected_mask = None
        self.app.selected_label = None
        self.app.selected_line = None

    def _handle_mask_drag(self, event):
        """处理遮罩拖拽绘制"""
        if not self.app.mask_drawing or not self.app.mask_start_pos:
            return
            
        # 清除临时遮罩
        if self.app.temp_mask_id:
            self.app.canvas.delete(self.app.temp_mask_id)
        
        # 计算当前位置
        current_pos = (event.x / self.app.scale, event.y / self.app.scale)
        
        # 计算矩形边界
        x1 = min(self.app.mask_start_pos[0], current_pos[0]) * self.app.scale
        y1 = min(self.app.mask_start_pos[1], current_pos[1]) * self.app.scale
        x2 = max(self.app.mask_start_pos[0], current_pos[0]) * self.app.scale
        y2 = max(self.app.mask_start_pos[1], current_pos[1]) * self.app.scale
        
        # 绘制临时遮罩预览
        mask_color = self.app._get_transparent_color(self.app.mask_color, self.app.mask_opacity)
        self.app.temp_mask_id = self.app.canvas.create_rectangle(
            x1, y1, x2, y2, fill=mask_color, outline="#007acc", 
            width=2, dash=(3, 3), stipple="gray50"
        )

    def _finish_mask_drawing(self, event):
        """完成遮罩绘制"""
        if not self.app.mask_drawing or not self.app.mask_start_pos:
            return
            
        # 清除临时遮罩
        if self.app.temp_mask_id:
            self.app.canvas.delete(self.app.temp_mask_id)
            self.app.temp_mask_id = None
        
        # 计算最终位置和尺寸
        end_pos = (event.x / self.app.scale, event.y / self.app.scale)
        
        x = min(self.app.mask_start_pos[0], end_pos[0])
        y = min(self.app.mask_start_pos[1], end_pos[1])
        width = abs(end_pos[0] - self.app.mask_start_pos[0])
        height = abs(end_pos[1] - self.app.mask_start_pos[1])
        
        # 只有在尺寸足够大时才创建遮罩
        if width > 10 and height > 10:
            from models import MaskItem
            mask = MaskItem(x, y, width, height, self.app.mask_color, self.app.mask_opacity)
            self.app.masks.append(mask)
            self.app.selected_mask = mask
            self.app.refresh_mask_list(select_last=True)
        
        # 重置状态
        self.app.mask_drawing = False
        self.app.mask_start_pos = None
        self.app.update_preview()

    def toggle_mask_mode(self):
        """切换遮罩模式"""
        self.app.mask_mode = not self.app.mask_mode
        
        # 清除其他模式
        if self.app.mask_mode:
            self.app.line_mode = False
            self.clear_temp_line_state()
        
        # 清除绘制状态
        self.app.mask_drawing = False
        self.app.mask_start_pos = None
        if self.app.temp_mask_id:
            self.app.canvas.delete(self.app.temp_mask_id)
            self.app.temp_mask_id = None
        
        # 更新按钮状态
        self.app.ui_builder._update_mask_button_state()
        
        from tkinter import messagebox
        from config import APP_TITLE
        mode_text = "开启" if self.app.mask_mode else "关闭"
        messagebox.showinfo(APP_TITLE, f"遮罩模式: {mode_text}")

    def on_mask_list_select(self, event):
        """遮罩列表选择事件"""
        try:
            selection = self.app.mask_list.curselection()
            if selection:
                idx = selection[0]
                if 0 <= idx < len(self.app.masks):
                    self.app.selected_mask = self.app.masks[idx]
                    # 清除其他选择
                    self.app.selected_label = None
                    self.app.selected_line = None
                    # 同步UI设置
                    self._sync_ui_with_selected_mask()
                    self.app.update_preview()
        except:
            pass

    def _sync_ui_with_selected_mask(self):
        """同步UI设置与选中的遮罩"""
        if not self.app.selected_mask:
            return
        
        # 临时标记，避免触发回调
        self.app._syncing_mask_ui = True
        
        try:
            # 更新遮罩颜色预览
            if hasattr(self.app, 'mask_color_preview'):
                self.app.mask_color_preview.configure(bg=self.app.selected_mask.color)
                self.app.mask_color = self.app.selected_mask.color
            
            # 更新透明度滑块
            if hasattr(self.app, 'mask_opacity_var'):
                self.app.mask_opacity_var.set(self.app.selected_mask.opacity)
                self.app.mask_opacity = self.app.selected_mask.opacity
        finally:
            # 清除临时标记
            self.app._syncing_mask_ui = False

    def update_selected_mask(self):
        """更新选中的遮罩属性"""
        if not self.app.selected_mask:
            return
        
        # 如果正在同步UI，跳过更新以避免循环
        if getattr(self.app, '_syncing_mask_ui', False):
            return
            
        # 更新颜色
        if hasattr(self.app, 'mask_color'):
            self.app.selected_mask.color = self.app.mask_color
        
        # 更新透明度
        if hasattr(self.app, 'mask_opacity_var'):
            self.app.selected_mask.opacity = self.app.mask_opacity_var.get()
            self.app.mask_opacity = self.app.mask_opacity_var.get()
        
        # 刷新显示
        self.app.refresh_mask_list()
        self.app.update_preview()
    
    def _update_current_font_path(self):
        """更新当前字体路径"""
        if hasattr(self.app, 'font_var') and self.app.font_var.get():
            selected_font_name = self.app.font_var.get()
            for font_path in self.app.available_fonts:
                if os.path.basename(font_path) == selected_font_name:
                    self.app.current_font_path = font_path
                    break

    def _is_point_in_label(self, x, y, label):
        """检查点是否在标注范围内"""
        try:
            from PIL import ImageFont
            # 使用PIL字体计算文字尺寸
            if label.font_path and os.path.exists(label.font_path):
                font = ImageFont.truetype(label.font_path, label.font_size)
            else:
                font = ImageFont.load_default()
            
            # 获取文字边界框
            bbox = font.getbbox(label.text)
            text_width = bbox[2] - bbox[0]
            text_height = bbox[3] - bbox[1]
            
            # 添加一些边距使点击更容易
            margin = 5
            return (label.x - margin <= x <= label.x + text_width + margin and
                    label.y - margin <= y <= label.y + text_height + margin)
        except:
            # 如果字体计算失败，使用估算值
            estimated_width = len(label.text) * label.font_size * 0.6
            estimated_height = label.font_size * 1.2
            margin = 5
            return (label.x - margin <= x <= label.x + estimated_width + margin and
                    label.y - margin <= y <= label.y + estimated_height + margin)

    def _sync_ui_with_selected_label(self):
        """同步UI控件与选中的标注"""
        if not self.app.selected_label:
            return
        
        # 临时标记，避免触发回调
        self.app._syncing_label_ui = True
        
        try:
            # 更新文字内容
            if hasattr(self.app, 'text_var'):
                self.app.text_var.set(self.app.selected_label.text)
            
            # 更新字号
            if hasattr(self.app, 'size_var'):
                self.app.size_var.set(self.app.selected_label.font_size)
            
            # 更新加粗状态
            if hasattr(self.app, 'bold_var'):
                self.app.bold_var.set(self.app.selected_label.bold)
            
            # 更新颜色
            if hasattr(self.app, 'color_preview'):
                self.app.color_preview.configure(bg=self.app.selected_label.color)
            
            # 更新字体选择
            if hasattr(self.app, 'font_var') and self.app.selected_label.font_path:
                font_name = os.path.basename(self.app.selected_label.font_path)
                self.app.font_var.set(font_name)
        finally:
            # 清除临时标记
            self.app._syncing_label_ui = False
        
        # 更新标注列表选择
        try:
            if hasattr(self.app, 'label_list') and self.app.selected_label in self.app.labels:
                idx = self.app.labels.index(self.app.selected_label)
                self.app.label_list.selection_clear(0, tk.END)
                self.app.label_list.selection_set(idx)
                self.app.label_list.see(idx)
        except:
            pass

    def _quick_update_canvas(self):
        """快速更新画布 - 仅重绘，不刷新列表"""
        if not self.app.image:
            return
            
        # 清理线条图像缓存
        self.app.clear_line_image_cache()
            
        # 清空画布
        self.app.canvas.delete("all")
        
        # 创建图像
        self.app.canvas.create_image(0, 0, anchor=tk.NW, image=self.app.tk_img)
        
        # 绘制标注 - 按层级顺序：遮罩 -> 线条 -> 标签
        for mask in self.app.masks:
            self.app._draw_mask(mask)
        for ln in self.app.lines:
            self.app._draw_line(ln)
        for lbl in self.app.labels:
            self.app._draw_label(lbl)
        
        # 更新滚动区域
        self.app.canvas.configure(scrollregion=self.app.canvas.bbox("all"))

    def _finish_line_drawing(self):
        """完成线条绘制"""
        self.app.temp_line_points.clear()
        self._clear_temp_line_preview()
        self.app.refresh_line_list(select_last=True)
        self.app.update_preview()

    def _clear_temp_line_preview(self):
        """清除临时线条预览"""
        for cid in self.app.temp_line_canvas_ids:
            self.app.canvas.delete(cid)
        self.app.temp_line_canvas_ids.clear()

    def _update_temp_line_preview(self):
        """更新临时线条预览"""
        self._clear_temp_line_preview()
        
        if not self.app.temp_line_points:
            return
        
        # 绘制已确定的点
        for point in self.app.temp_line_points:
            x = int(point[0] * self.app.scale)
            y = int(point[1] * self.app.scale)
            cid = self.app.canvas.create_oval(x-3, y-3, x+3, y+3, 
                                            fill="#0080ff", outline="#0080ff")
            self.app.temp_line_canvas_ids.append(cid)
        
        # 绘制已确定的线段
        if len(self.app.temp_line_points) >= 2:
            for i in range(len(self.app.temp_line_points) - 1):
                x1 = int(self.app.temp_line_points[i][0] * self.app.scale)
                y1 = int(self.app.temp_line_points[i][1] * self.app.scale)
                x2 = int(self.app.temp_line_points[i+1][0] * self.app.scale)
                y2 = int(self.app.temp_line_points[i+1][1] * self.app.scale)
                # 使用抗锯齿绘制临时线条
                self.app.canvas.create_line(x1, y1, x2, y2, 
                                          fill="#0080ff", width=2, dash=(3, 2),
                                          smooth=True, capstyle=tk.ROUND, splinesteps=12)
                # 添加半透明辅助线减少锯齿
                cid1 = self.app.canvas.create_line(x1+0.5, y1+0.5, x2+0.5, y2+0.5, 
                                                 fill="#80b3ff", width=1, dash=(3, 2),
                                                 smooth=True, capstyle=tk.ROUND)
                cid2 = self.app.canvas.create_line(x1-0.5, y1-0.5, x2-0.5, y2-0.5, 
                                                 fill="#80b3ff", width=1, dash=(3, 2),
                                                 smooth=True, capstyle=tk.ROUND)
                self.app.temp_line_canvas_ids.extend([cid1, cid2])

    def _handle_mask_resize(self, event):
        """处理遮罩调整大小"""
        if not self.app.resizing_mask or not self.app.resize_handle:
            return
        
        mask = self.app.resizing_mask
        handle = self.app.resize_handle
        
        # 转换为图像坐标
        mouse_x = event.x / self.app.scale
        mouse_y = event.y / self.app.scale
        
        # 根据拖动的手柄调整遮罩尺寸
        if handle == 'tl':  # 左上角
            new_width = mask.x + mask.width - mouse_x
            new_height = mask.y + mask.height - mouse_y
            if new_width > 5 and new_height > 5:
                mask.width = new_width
                mask.height = new_height
                mask.x = mouse_x
                mask.y = mouse_y
        elif handle == 'tr':  # 右上角
            new_width = mouse_x - mask.x
            new_height = mask.y + mask.height - mouse_y
            if new_width > 5 and new_height > 5:
                mask.width = new_width
                mask.height = new_height
                mask.y = mouse_y
        elif handle == 'bl':  # 左下角
            new_width = mask.x + mask.width - mouse_x
            new_height = mouse_y - mask.y
            if new_width > 5 and new_height > 5:
                mask.width = new_width
                mask.height = new_height
                mask.x = mouse_x
        elif handle == 'br':  # 右下角
            new_width = mouse_x - mask.x
            new_height = mouse_y - mask.y
            if new_width > 5 and new_height > 5:
                mask.width = new_width
                mask.height = new_height
        
        # 快速更新画布
        self._quick_update_canvas()

    def _handle_mask_move(self, event):
        """处理遮罩拖动移动"""
        if not self.app.dragging_mask or not self.app.mask_drag_offset:
            return
        
        mask = self.app.dragging_mask
        
        # 计算新位置（考虑拖动偏移量）
        new_x = (event.x - self.app.mask_drag_offset[0]) / self.app.scale
        new_y = (event.y - self.app.mask_drag_offset[1]) / self.app.scale
        
        # 限制拖动范围，防止拖出图像边界
        if self.app.image:
            iw, ih = self.app.image.size
            new_x = max(0, min(new_x, iw - mask.width))
            new_y = max(0, min(new_y, ih - mask.height))
        
        mask.x = new_x
        mask.y = new_y
        
        # 快速更新画布
        self._quick_update_canvas()
